package com.ifacebox.arcsoft.face;

import com.arcsoft.face.ActiveFileInfo;
import com.arcsoft.face.EngineConfiguration;
import com.arcsoft.face.FunctionConfiguration;
import com.arcsoft.face.enums.DetectMode;
import com.arcsoft.face.enums.DetectOrient;
import org.apache.commons.pool2.*;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author znn
 */
@Configuration
public class ArcSoftFaceConfig {
    private static final Logger logger = LoggerFactory.getLogger(ArcSoftFaceConfig.class);
    @Resource
    private ArcSoftFaceConfigProperties faceConfigProperties;

    @Bean
    public FunctionConfiguration functionConfiguration() {
        FunctionConfiguration functionConfiguration = new FunctionConfiguration();
        functionConfiguration.setSupportFaceDetect(true);
        functionConfiguration.setSupportFaceRecognition(true);
        functionConfiguration.setSupportAge(false);
        functionConfiguration.setSupportGender(false);
        functionConfiguration.setSupportFace3dAngle(false);
        functionConfiguration.setSupportLiveness(faceConfigProperties.isSupportLiveness());
        functionConfiguration.setSupportIRLiveness(false);
        return functionConfiguration;
    }

    @Bean
    public EngineConfiguration engineConfiguration(FunctionConfiguration functionConfiguration) {
        EngineConfiguration engineConfiguration = new EngineConfiguration();
        engineConfiguration.setFunctionConfiguration(functionConfiguration);
        engineConfiguration.setDetectFaceMaxNum(10);
        engineConfiguration.setDetectFaceScaleVal(30);
        engineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);
        engineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY);
        return engineConfiguration;
    }

    @Bean
    public BasePooledObjectFactory<ArcSoftFaceEngine> basePooledObjectFactory(EngineConfiguration engineConfiguration) {
        return new BasePooledObjectFactory<ArcSoftFaceEngine>() {
            @Override
            public ArcSoftFaceEngine create() throws Exception {
                ArcSoftFaceEngine faceEngine = new ArcSoftFaceEngine(faceConfigProperties.getLibPath());
                ActiveFileInfo activeFileInfo = faceEngine.create(faceConfigProperties.getAppId(), faceConfigProperties.getSdkKey(), engineConfiguration);
                if (logger.isInfoEnabled()) {
                    logger.info("{}\t{} for {} by v{} and v{} expires ({} ~ {})"
                            , faceEngine.hashCode(), activeFileInfo.getSdkType(), activeFileInfo.getPlatform(), activeFileInfo.getSdkVersion(), activeFileInfo.getFileVersion()
                            , new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date(Long.parseLong(activeFileInfo.getStartTime()) * 1000))
                            , new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(new Date(Long.parseLong(activeFileInfo.getEndTime()) * 1000))
                    );
                }
                return faceEngine;
            }

            @Override
            public PooledObject<ArcSoftFaceEngine> wrap(ArcSoftFaceEngine faceEngine) {
                return new DefaultPooledObject<>(faceEngine);
            }

            @Override
            public void destroyObject(PooledObject<ArcSoftFaceEngine> pooledObject, DestroyMode destroyMode) throws Exception {
                ArcSoftFaceEngine faceEngine = pooledObject.getObject();
                faceEngine.destroy();
            }
        };
    }

    @Bean
    public GenericObjectPoolConfig<ArcSoftFaceEngine> genericObjectPoolConfig() {
        GenericObjectPoolConfig<ArcSoftFaceEngine> genericObjectPoolConfig = new GenericObjectPoolConfig<>();
        genericObjectPoolConfig.setMaxIdle(faceConfigProperties.getFaceMaxThreads());
        genericObjectPoolConfig.setMinIdle(faceConfigProperties.getFaceMaxThreads());
        genericObjectPoolConfig.setMaxTotal(faceConfigProperties.getFaceMaxThreads());
        genericObjectPoolConfig.setMaxWait(faceConfigProperties.getFaceMaxWait());
        genericObjectPoolConfig.setJmxEnabled(false);
        return genericObjectPoolConfig;
    }

    @Bean
    public GenericObjectPool<ArcSoftFaceEngine> genericObjectPool(BasePooledObjectFactory<ArcSoftFaceEngine> basePooledObjectFactory
            , GenericObjectPoolConfig<ArcSoftFaceEngine> genericObjectPoolConfig) {
        return new GenericObjectPool<>(basePooledObjectFactory, genericObjectPoolConfig);
    }
}
